DATA segment
            dw 85, 98, 79, 100, 57, 0, 0, 0
            dw 'aa', 'bb', 'cc', 'dd', 'ee', 0, 0, 0
    prompt1 db 13, 10, 'input name: (2 char)', 13, 10, '$'
    prompt2 db 13, 10, 'input score: (0-100)', 13, 10, '$'
    prompt3 db 13, 10, 'Score Wrong! Enter again: ', 13, 10, '$'
DATA ends
STACK segment
          dw 16 dup(0)
STACK ends
CODE segment
                ASSUME CS:CODE, DS:DATA, SS:STACK
    start:      mov    ax, DATA
                mov    ds, ax

                mov    ax, STACK
                mov    ss, ax
                mov    sp, 32

    
                

    ; 获取用户输入
                mov    si, 0
                mov    cx, 5
    input:      push   cx
                
                mov    bx, 0                         ; 用bx存当前获得结果
                
    ; 提示用户输入姓名
                lea    dx, prompt1
                mov    ah, 9
                int    21h

                call   inputName
                mov    ds:[si+16], bx                ; 保存获取完的姓名

    ; 提示用户输入成绩
    againScore: 
                lea    dx, prompt2
                mov    ah, 9
                int    21h

                mov    cl, 10                        ; 存10, 以便每次用cl乘al
                mov    bx, 0
                call   inputNum
                cmp    bx, 100
                jbe    continue
    ; 如果没继续说明有错误
                lea    dx, prompt3
                mov    ah, 9
                int    21h
                jmp    againScore

    continue:   mov    ds:[si], bx                   ; 保存获取完的成绩

                add    si, 2
                pop    cx
                loop   input

    ; 排序
                mov    cx, 4                         ; 外循环4次
    outer:      push   cx
                mov    si, 0                         ; 控制分数
                mov    di, 16                        ; 控制名字
    ;内循环次数为当前cx
    inner:      mov    bp, ds:[si]
                cmp    word ptr bp, ds:[si+2]
                ja     Go                            ;相当于continue, 不执行下面两条语句
                xchg   bp, ds:[si+2]                 ; 交换分数
                mov    ds:[si], bp

                mov    dx, ds:[di]                   ; 借助dx交换
                xchg   dx, ds:[di+2]
                mov    ds:[di], dx
    Go:         add    si, 2
                add    di, 2
                loop   inner
                pop    cx
                loop   outer

    ; 输出
                mov    bh,10
                mov    cx, 5
                mov    si, 0
    output:     call   outputName
                mov    ah, 2
                mov    dl, ' '
                int    21h
                call   outputScore
                mov    dl, 10
                int    21h
                add    si, 2
                loop   output

                mov    ax, 4c00h
                int    21h
        

inputNum proc
    next:       
                mov    ah, 1                         ; 键盘输入一个字符, 有回显
                int    21h
    ; 判断字符是否是数字
                cmp    al, '0'
                jb     over
                cmp    al, '9'
                ja     over
            
                sub    al, 48                        ; 字符变为数字
                mov    dl, al                        ; 用dl暂存输入数字
                mov    dh, 0
                mov    al, bl                        ; bl里的数挪到al里做乘法
                mul    cl
                add    ax, dx                        ; 用本次输入的数据加上上次输入的数据
                mov    bx, ax                        ; 继续用bx存储组合好的数据
                jmp    next
    over:       cmp    al, 13
                je     continue2
                lea    dx, prompt3
                mov    ah, 9
                int    21h
                pop    cx                            ; 正常来讲ret会弹出ip但是通过jmp就不弹出，所以手动弹出
                jmp    againScore
    continue2:  ret
inputNum endp
inputName proc
                mov    ah, 1
                int    21h
                mov    bl, al
                int    21h
                mov    bh, al
                ret
inputName endp
outputScore proc                                     ;输出函数
                mov    bl,0                          ; 统计当前数字有几个十进制位
                mov    ax,ds:[si]
    inStack:    div    bh
                push   ax                            ;入栈
                add    bl,1                          ;计数器加一
                mov    ah,0
                cmp    ax,0                          ;当被除数为0时结束循环
                jne    inStack
    outStack:   pop    dx                            ;出栈
                sub    bl,1                          ;计数器减一
                mov    dl,dh
                add    dl,48
                mov    ah,2
                int    21h
                cmp    bl,0                          ;当计数器清零时结束循环
                jne    outStack
                ret
outputScore endp
outputName proc
                mov    ah, 2
                mov    dl, ds:[16+si]
                int    21h
                mov    dl, ds:[17+si]
                int    21h
                ret
outputName endp
              

CODE ends
end start